NMock2 as a code exploration tool

A co-worker (Jason Kerney) and I have been messing around with NMock2 in C# for a while now, and we’ve put together an introductory presentation on the basics of using NMock2 that we are going to give at the upcoming Code Camp at Cal State Fullerton.  [January 25th & 26th, 2008 – Code Camp is a free conference put on by developers for developers].

This article is not our presentation, but rather a little introduction about using NMock2 for doing exploratations into existing code.

You are probably familiar with using assertions in NUnit tests.  Assertions reveal in what way the object and/or some other collaborating object has changed during an operation by cheking state, and are also used to verify the result returned from an operation. Mock objects, on the other hand, provide a way to test the behaviors of code. That is, mock objects test what the object is or isn’t doing.  Mock objects are often used together with assertions to better pin down the code under test.

Mock objects provide this ability through “expectations”. Essentially, we “Expect” an object to do certain things with an object it is collaborating with. This is nifty. What this means is that we can verify how one object (our “code-under-test”, or CUT) interacts with another object (our “depended-on-compnent”, or DOC) by using a mock object in place of the DOC. The mock obejct is wired up with the things we “Expect”, and then alerts us when things are not done as we expect. (The mechanics of using NMocks2 for dynamic mock objects can be found at the NMock2 site.)

There are a number of ways mock objects are useful, and the one I’m showing here is how we’ve been using dynamic mock objects for explorating existing, foggy code. You can think of this use as a “discovery” or “probing” tool similar to a robot being sent into a burning building or to Mars or to some other place a human can’t, shouldn’t, or doesn’t get paid enough to go to do things the human couldn’t do anyway even if the could go there.  In this case, we are sending the mock object into code that our typcial “state” style testing can’t inspect.

The basic steps are as follows:

– Write an NUnit test method to contain the exploratory code
– Create a mock object to use in place of a DOC (depended on object) the CUT (code under test) uses, but don’t write any Expect call yet – we want all calls to cause an “unexpected invocation” error. This is what we use to probe the CUT for calls to the DOC. NOTE: NMock2 can supply a mock object only for an interface, and not for a class – so the objects you are mocking must implement an interface.
– There might be some refactoring to do to set this all up since we need a way to have control of the DOC – There are several safe refactorings to accomplish this – I don’t cover that here, but will be happy to do so in another post if someone is interested. Take a look at Michael Feathers “Working Effectively with Legacy Code” book.
– Instantiate the object that is the target of our test (that is, an object that contains the operation that is our CUT)
– Write code to make a call on the method we are testing.
– Now we can start probing by running the test.  In running the test the first call from the CUT to the DOC will produce an “unexpected invocation” error.  This means the DOC has been called in a way that we haven’t told it to expect.  Since we haven’t told it to expect anything, it is no surprise to us that we get this error – this is the result of our probe.
– Using the info in the “unexpected invocation” error message, write an Expect to fulfill the expectation.  I show this in the example below.
– Run the test again, and the next “unexpected invocation” error should appear.
– You fix that with another Expect, just like before.
– Then you just continue doing this until there are no more “unexpected invocation” errors.
– If there is more than one DOC used by the CUT, then youl might need a mock object for each one depending on what you are trying to do, but the process is the same.
– Eventually you’ll have a way to test the CUT in complete isolation. Which is where most of us work anyway, I suppose.

Here is a trivial example: Let’s say we have a dice game that has a class named “Turn” that has a dependency on a class named “Cup”. A Turn object represents a turn of a player, and a Cup object “holds” and operates on the set of dice that are tossed during the game. To learn how Turn uses Cup, will will set up an NUnit test like the one that follows. If Cup is not currently implementing an interface that we can use, we’ll need to extract its interface before we can use it to set up a mock object.

[Test] 
public void discoverHowTurnUsesCup () 
{ 
    // Create World 
    Mockery mockery = new Mockery(); 
    ICup cupMock = mockery.NewMock<ICup>();    

    // Turn contains the code under test 
    Turn turn = new Turn(cupMock);      

    // Call a method on Turn - the CUT 
    turn.take(); 
}

Thats all you need to do to start exploring.  Exciting, isn’t it?

Note that this code is only testing an instance of the Turn class. The dependency on a concrete Cup object has been replaced with our cupMock.

In running that test we will discover that turn.take makes a call to cup.Throw, or something like that. The error message will look something like this:

GameTest.TestTurn.discoverHowTurnUsesCup : 
NMock2.Internal.ExpectationException : 
unexpected invocation of cup.Throw(<3>) 
Expected:

So now we can add an expectation. This uses the static methods on the NMock2 Expect class:

Expect. 
    Once. 
    On(cupMock). 
    Method("Throw"). 
    With(Is.EqualTo(3));

This is saying that we will call the Throw method on a Cup object passing in a value of 3. (three might be the number of dice used in the game… who knows, and in this case it really isn’t important – we just need to know that a value of 3 is being passed in). As you can see, “Throw” is a string, and as you probably can guess NMock uses reflection to do its work.  The call to With tells NMock that there will be one parameter with a value of 3 (this is known as a matcher). You can use as many parameters as you need.

Here is how the code will look after we have added the expectation:

[Test] 
public void discoverHowTurnUsesCup () 
{     

    Mockery mockery = new Mockery(); 
    ICup cupMock = mockery.NewMock<ICup>(); 
    // Our new expectation to fulfill the 
    //     unexpected invocation our probe revealed 
    Expect. 
        Once. 
        On(cupMock). 
        Method("Throw"). 
        With(Is.EqualTo(3));      

        Turn turn = new Turn(cupMock);          

        turn.take();          

}

Now we run the test again to find the next “unexpected invocation”, if there is one. And the following message reveals one:

GameTest.TestTurn.discoverHowTurnUsesCup : 
NMock2.Internal.ExpectationException : 
unexpected invocation of cup.GetScore() 
Expected:

You know the ropes now – so it is easy to see that we need to Expect a call on Cup named GetScore. Easy enough. We can see that GetScore does not use parameters, sowith a slight difference from the previous Expect:

[Test] 
public void discoverHowTurnUsesCup() 
{ 
    Mockery mockery = new Mockery(); 
    ICup cupMock = mockery.NewMock<ICup>(); 
    Expect.Once.On(cupMock). 
        Method("Throw"). 
        With(Is.EqualTo(3)); 
    // Another expectation to fulfill the 
    //     second probe 
    Expect.Once.On(cupMock). 
        Method("GetScore"). 
        WithNoArguments();                    

    Turn turn = new Turn(cupMock); 
    turn.Take();                    

    mockery.VerifyAllExpectationsHaveBeenMet(); 
}

You will notice that this new Expect uses the WithNoArguments method to indicate that we expect to have no arguments. Makes sense. Now, with a name like GetScore there will probably be a return value, but I didn’t code for that yet. Let’s run the test and see the next error.

GameTest.TestTurn.discoverHowTurnUsesCup : 
System.Runtime.Remoting.RemotingException : 
ByRef value type parameter cannot be null.

Okay – that is a little cryptic, but it’s telling us that we need to expect a return value… so let’s code this up, get it working, and go to lunch. In NMock2, an expected return value is coded as an Action using the Will method, coupled onto our growing Expect.

[Test] 
public void discoverHowTurnUsesCup() 
{ 
    Mockery mockery = new Mockery(); 
    ICup cupMock = mockery.NewMock<ICup>(); 
    Expect.Once.On(cupMock). 
        Method("Throw"). 
        With(Is.EqualTo(3)); 
    // Here we've added the required action 
    //     using the Will method 
    Expect.Once.On(cupMock). 
        Method("GetScore"). 
        WithNoArguments(). 
        Will(Return.Value(5));                    

        Turn turn = new Turn(cupMock); 
        turn.Take();                    

}

That works nicely. Return.Value(5) is an action that the mock object will take when it is called. in this case, the action is to return the arbitrary value of 5. For our current purpose, an arbitrary value if fine, but in real life there might be validations done on that value and tests should be put into place that can sense that, or perhaps we’ll see an error thrown from inside Turn that will alert us to the fact that we can write a test for both the happy and sad paths. For this little example, that is enough.

But… there is still one thing left to do. We are exploring here, so we are certain that everything is getting called that we expect to get called because we created those expectations based on failing tests. But as we go forward and start to fix or refactor the code-under-test we need to prove that all expectations are invoked – that is, we need a way to prove that every call we are expecting actually occurs. There is an easy way to do this using a method on the Mockery class:

mockery.VerifyAllExpectationsHaveBeenMet()

After adding this to the code in our NUnit test method discoverHowTurnUsesCup, it will now look like this:

[Test] 
public void discoverHowTurnUsesCup () 
{ 
    Mockery mockery = new Mockery(); 
    ICup cupMock = mockery.NewMock<ICup>(); 
    Expect.Once.On(cupMock). 
        Method("Throw"). 
        With(Is.EqualTo(3)); 
    Expect.Once.On(cupMock). 
        Method("GetScore"). 
        WithNoArguments(). 
        Will(Return.Value(5));                  

    Turn turn = new Turn(cupMock); 
    turn.Take();                    

    // Let's make sure that everything we expect 
    //   has happended 
    mockery.VerifyAllExpectationsHaveBeenMet(); 
}

So there you have it. Mock objects make it very easy to discover how your dependencies are being used,  and as you probe using this technique you are building a characterization test that pins down the behavior of the CUT.  There are some side benefits to doing this.  One is that you are automatically documenting how the CUT goes about collaborating with other objets, and it’s in a relatively easy to read format.  Another benefit is that this process forces you to find a way to decouple your code. You can do this very conservatively at first with safe refactorings like extract getter and extract interface. The stronger your suite of automated unit tests, the more daring your refactorings can become. This allows you to start using evolutionary design as you maintain your code – which is something I have found to be critical in keeping code from falling into an un-maintainable state. But that is for some other article sometime.